package com.yykj.hospital.server.service.open.impl;

import com.yykj.common.constant.CommonConstant;
import com.yykj.common.enums.HospitalOnlineTypeEnum;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.common.util.PageRequestUtil;
import com.yykj.common.vo.PageData;
import com.yykj.hospital.client.form.open.OpenDoctorSearchForm;
import com.yykj.hospital.client.vo.open.OpenDoctorListVO;
import com.yykj.hospital.server.model.entity.DoctorOnlinePriceSetting;
import com.yykj.hospital.server.model.entity.HospitalDoctor;
import com.yykj.hospital.server.model.repository.DoctorOnlinePriceSettingRepository;
import com.yykj.hospital.server.model.repository.HospitalDoctorRepository;
import com.yykj.hospital.server.service.open.OpenService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.util.*;

@Service
public class OpenServiceImpl implements OpenService {
    @Override
    public PageData<OpenDoctorListVO> openSearchDoctor(OpenDoctorSearchForm form) {
        BigDecimal minPrice = null;
        BigDecimal maxPrice = null;
        if (form.getHospitalId() == null || form.getHospitalId() <= 0) {
            throw new NormalException(ResultEnums.PARAM_ERROR, "hospitalId不能为空");
        }

        if (!StringUtils.isEmpty(form.getMinPrice())) {
            try {
                minPrice = new BigDecimal(form.getMinPrice());
            } catch (Exception e) {
                throw new NormalException(ResultEnums.PARAM_ERROR, "价格非法");
            }
        }
        if (!StringUtils.isEmpty(form.getMaxPrice())) {
            try {
                maxPrice = new BigDecimal(form.getMaxPrice());
            } catch (Exception e) {
                throw new NormalException(ResultEnums.PARAM_ERROR, "价格非法");
            }
        }
        Set<String> doctorIds = new HashSet<>();
        Map<String, BigDecimal> priceMap = new HashMap<>();
        boolean needCheckPrice = false;
        if (minPrice != null || maxPrice != null) {
            needCheckPrice = true;
            List<DoctorOnlinePriceSetting> settingList = doctorOnlinePriceSettingRepository.findAllByHospitalIdAndType(form.getHospitalId(), HospitalOnlineTypeEnum.video);
            for (DoctorOnlinePriceSetting setting : settingList) {
                priceMap.put(setting.getDoctorId(), setting.getPrice());
                if (minPrice != null && minPrice.compareTo(setting.getPrice()) <= 0 && maxPrice == null) {
                    doctorIds.add(setting.getDoctorId());
                }

                if (minPrice != null && maxPrice != null && minPrice.compareTo(setting.getPrice()) <= 0
                        && maxPrice.compareTo(setting.getPrice()) >= 0) {
                    doctorIds.add(setting.getDoctorId());
                }

                if (maxPrice != null && maxPrice.compareTo(setting.getPrice()) >= 0 && minPrice == null) {
                    doctorIds.add(setting.getDoctorId());
                }
            }
        }
        PageData<OpenDoctorListVO> result = new PageData<>();
        if (needCheckPrice && doctorIds.size() == 0) {
            result = PageData.defaultPageData(PageRequestUtil.getPage(form.getCurrentPage()),
                    PageRequestUtil.getSize(form.getPageSize()));
            return result;
        }


        PageRequest pageRequest = PageRequest.of(PageRequestUtil.getPage(form.getCurrentPage()),
                PageRequestUtil.getSize(form.getPageSize()), Sort.by(Sort.Order.desc("sorting")));
        Page<HospitalDoctor> list = hospitalDoctorRepository.findAll(generateSpecification(form, doctorIds, needCheckPrice), pageRequest);


        List<OpenDoctorListVO> openList = new ArrayList<>();
        for (HospitalDoctor doctor : list) {
            OpenDoctorListVO vo = new OpenDoctorListVO();
            BeanUtils.copyProperties(doctor, vo);
            if (priceMap.get(doctor.getDoctorId()) == null) {
                vo.setPrice(CommonConstant.VOICE_PRICE);
            } else {
                vo.setPrice(priceMap.get(doctor.getDoctorId()));
            }
            openList.add(vo);
        }
        result.setCurrentPage(PageRequestUtil.getPage(form.getCurrentPage()) + 1);
        result.setPageSize(PageRequestUtil.getSize(form.getPageSize()));
        result.setTotalCount(list.getTotalElements());
        result.setTotalPage(list.getTotalPages());

        result.setList(openList);
        return result;


    }

    private Specification<HospitalDoctor> generateSpecification(OpenDoctorSearchForm form, Set<String> doctorIds, boolean needCheckPrice) {
        return new Specification<HospitalDoctor>() {
            @Override
            public Predicate toPredicate(Root<HospitalDoctor> root, CriteriaQuery<?> query, CriteriaBuilder builder) {

                List<Predicate> predicateList = new ArrayList<>();
                predicateList.add(builder.equal(root.get("hospitalId"), form.getHospitalId()));
                if (!StringUtils.isEmpty(form.getOfficer())) {
                    predicateList.add(builder.equal(root.get("officer"), form.getOfficer()));
                }
                if (form.getDepId() != null && form.getDepId() > 0) {
                    predicateList.add(builder.equal(root.get("depId"), form.getDepId()));
                }

                if (needCheckPrice && doctorIds != null && doctorIds.size() > 0) {
                    CriteriaBuilder.In<String> in = builder.in(root.get("doctorId"));
                    for (String id : doctorIds) {
                        in.value(id);
                    }
                    predicateList.add(in);
                }

                Predicate[] predicates = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicates)).getRestriction();
            }
        };
    }

    private EntityManager em;

    private HospitalDoctorRepository hospitalDoctorRepository;

    private DoctorOnlinePriceSettingRepository doctorOnlinePriceSettingRepository;

    @Autowired
    public void setEm(EntityManager em) {
        this.em = em;
    }

    @Autowired
    public void setHospitalDoctorRepository(HospitalDoctorRepository hospitalDoctorRepository) {
        this.hospitalDoctorRepository = hospitalDoctorRepository;
    }

    @Autowired
    public void setDoctorOnlinePriceSettingRepository(DoctorOnlinePriceSettingRepository doctorOnlinePriceSettingRepository) {
        this.doctorOnlinePriceSettingRepository = doctorOnlinePriceSettingRepository;
    }
}
